<?php
/**
 * 
 * Base class for all apps
 * 
 * @category Abovo
 * 
 * @package Abovo
 * 
 * @author Antti Holvikari <anttih@gmail.com>
 * 
 * @license http://opensource.org/licenses/bsd-license.php BSD
 * 
 */

/**
 * 
 * Base app class for other apps
 * 
 * @category Abovo
 * 
 * @package Abovo_App
 * 
 */
abstract class Abovo_App_Base extends Solar_App_Base {
    
    /**
     * 
     * Config keys
     * 
     * @var string
     * 
     */
    protected $_Abovo_App_Base = array(
        'layout' => 'yui',
        'title'  => 'Abovo',
        'style' => array(
            'Abovo/styles/YUI/reset-fonts-grids.css',
            'Abovo/styles/forms.css',
            'Abovo/styles/main.css',
        ),
        
    );
    
    /**
     * 
     * Short name for module
     * 
     * @var string
     * 
     */
    protected $_module;
    
    /**
     * 
     * Module class name
     * 
     * @var string
     * 
     */
    public $module;
    
    /**
     * 
     * App class name
     * 
     * @var string
     * 
     */
    public $app;
    
    /**
     * 
     * Menu for current user handle
     * 
     * @var array
     * 
     */
    public $menu = array();
    
    /**
     * 
     * Sub menu items
     * 
     * @var array
     * 
     */
    public $layout_sub = array();
    
    /**
     * 
     * Active sub menu item
     * 
     * @var string
     * 
     */
    public $layout_sub_active;
    
    /**
     * 
     * Site-wide notification/success messages
     * 
     * @var array
     * 
     */
    public $msg_success = array();
    
    /**
     * 
     * Site-wide failure messages
     * 
     * @var array
     * 
     */
    public $msg_failure = array();
    
    /**
     * 
     * Error messages
     * 
     * @var array
     * 
     */
    public $errors = array();
    
    /**
     * 
     * Contact info about currently signed in user
     * 
     * @var Solar_Sql_Row
     * 
     */
    public $user;
    
    /**
     * 
     * undocumented function
     * 
     * @return void
     * 
     */
    public function __construct($config = null)
    {
        parent::__construct($config);
        
        // set app class name for view
        $this->app = get_class($this);
        
        // set short module name
        $parts = explode('_', $this->app);
        $this->_module = $parts[count($parts)-2];
        $this->_module = preg_replace('/([a-z])([A-Z])/', '$1-$2', $this->_module);
        $this->_module = strtolower($this->_module);
        
        // set layout
        $this->_layout = $this->_config['layout'];
        
        // @todo Move these to a template?
        
        // set title
        $this->layout_head['title'] = $this->_config['title'];
        
        // set meta tags
        $this->layout_head['meta'][] = array(
            'http-equiv' => 'Content-Type',
            'content'    => 'charset=utf-8',
        );
        
        // set layout styles
        $this->layout_head['style'] = (array) $this->_config['style'];
    }
    
    /**
     * 
     * Dump error messages
     * 
     * @return void
     * 
     */
    public function actionError()
    {
        // Just show the error view
    }
    
    /**
     * 
     * Run before each 'run'
     * 
     * @return void
     * 
     */
    protected function _preRun()
    {
        // menu object
        $menu = Solar::registry('menu');
        
        // is this app already known?
        if (! $menu->appExists($this->app)) {
            // add this app
            $menu->insert($this->app);
        }
        
        // signed in?
        if (! Solar::registry('user')->auth->isValid()) {
            // redirect to login page
            return $this->_redirect('system/user');
        }
        
        // fetch users info and make it available everywhere
        $users = Solar::factory('Abovo_Model_Contacts_Users');
        $this->user = $users->fetchByHandle(
            Solar::registry('user')->auth->handle
        );
    }
    
    /**
     * 
     * Checks to see if user is allowed access to the requested action
     * for this controller.
     * 
     * On access failure, changes $this->_action to 'error' and adds
     * an error message stating the user is not allowed access.
     * 
     * @return void
     * 
     */
    protected function _preAction()
    {
        $allow = Solar::registry('user')->access->isAllowed(
            get_class($this),
            $this->_action
        );
        
        if (! $allow) {
            $this->errors[] = $this->locale('ERR_ACCESS_NOT_ALLOWED');
            $this->_action = 'error';
        }
    }
    
    /**
     * 
     * Runs after _forward() chain
     * 
     * @return void
     * 
     */
    protected function _postRun()
    {
        // menu object
        $menu = Solar::registry('menu');
        
        // fetch menu if user is signed in
        if (Solar::registry('user')->auth->isValid()) {
            // fetch menu for user handle
            $this->menu = $menu->getAllByHandle(
                Solar::registry('user')->auth->handle
            );
        }
        
        // set current local menu element
        $this->layout_local_active = "{$this->_module}/{$this->_name}/{$this->_action}";
    }
    
    /**
     * 
     * Additional setup
     * 
     * @return void
     * 
     */
    protected function _setup()
    {
        parent::_setup();
        
        // register a Solar_Sql object if not already
        if (! Solar::isRegistered('sql')) {
            Solar::register('sql', Solar::factory('Solar_Sql'));
        }
        
        // register a Solar_Log object if not already
        if (! Solar::isRegistered('log')) {
            Solar::register('log', Solar::factory('Solar_Log'));
        }
        
        // register menu object if not already
        if (! Solar::isRegistered('menu')) {
            Solar::register('menu', Solar::factory('Abovo_Menu'));
        }
        
        // register a Solar_User object if not already.
        // this will trigger the authentication process.
        if (! Solar::isRegistered('user')) {
            Solar::register('user', Solar::factory('Solar_User'));
        }
    }
    
    /**
     * 
     * Write log for current app
     * 
     * @return whatever Solar_Log_Adapter::save()
     * returned
     * 
     */
    protected function _log($msg, $event = 'info')
    {
        // write log
        return Solar::registry('log')->save(
            $this->app,
            $event,
            $msg
        );
    }
    
    /**
     * 
     * Adds a notification/success message for view
     * 
     * This is useful when a flash message is read and
     * should be shown on the page.
     * 
     * @return void
     * 
     */
    protected function _msgSuccess($msg)
    {
        if (is_string($msg) && strlen($msg) > 0) {
            $this->msg_success[] = $msg;
        }
    }
    
    /**
     * 
     * Adds a failure message for view
     * 
     * This is useful when a flash message is read and
     * should be shown on the page.
     * 
     * @return void
     * 
     */
    protected function _msgFailure($msg)
    {
        if (is_string($msg) && strlen($msg) > 0) {
            $this->msg_failure[] = $msg;
        }
    }
    
    /**
     * 
     * Shows the "exception during fetch" page.
     * 
     * @param Exception $e The exception encountered during fetch().
     * 
     * @return Solar_Response A response object with a 500 status code and
     * a page describing the exception.
     * 
     */
    protected function _exceptionDuringFetch(Exception $e)
    {
        $this->errors[] = $e;
        $this->_layout = null;
        $this->_view = 'exception';
        $this->_format = null;
        $this->_response->setStatusCode(500);
        
        $this->_render();
        return $this->_response;
    }
    
    /**
     * 
     * Add this helper class to the stack
     * 
     * @var array
     * 
     */
    protected $_helper_class = array(
        'Abovo_View_Helper',
    );
    
    /**
     * 
     * Resets $this->_view_object to use the Layout templates.
     * 
     * This effectively re-uses the Solar_View object from the page
     * (with its helper objects and data) to build the layout.  This
     * helps to transfer JavaScript and other layout data back up to
     * the layout with zero effort.
     * 
     * Automatically sets up a template-path stack for you, searching
     * for layout files in this order ...
     * 
     * 1. Vendor/App/Example/Layout/
     * 
     * 2. Vendor/App/Layout/
     * 
     * 3. Solar/App/Layout/
     * 
     * @param Solar_View $view The Solar_View object to modify.
     * 
     * @return Solar_View
     * 
     */
    protected function _setLayoutTemplates()
    {
        // get the parents of the current class, including self
        $stack = Solar::parents(get_class($this), true);
        
        // remove Solar_Base and Solar_Controller_Page
        array_pop($stack);
        array_pop($stack);
        
        // convert underscores to slashes, and add /Layout
        foreach ($stack as $key => $val) {
            $stack[$key] = str_replace('_', '/', $val) . '/Layout';
        }
        
        // should we add Solar/App/Base/Layout for non-Solar vendors?
        
        // done, add the stack
        $this->_view_object->setTemplatePath($stack);
    }
}
